package com.hzw.saas.common.pay.unionpay;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Map;

import com.hzw.saas.common.pay.bean.TradeStatus;
import com.hzw.saas.common.pay.enums.PayType;
import com.hzw.saas.common.pay.enums.TradeStatusEnum;
import com.hzw.saas.common.pay.exception.TradeException;
import com.hzw.saas.common.pay.unionpay.bean.UnionPayReqContent;
import com.hzw.saas.common.pay.unionpay.bean.UnionQueryReqContent;
import com.hzw.saas.common.pay.unionpay.bean.UnionRefundReqContent;
import com.hzw.saas.common.pay.unionpay.config.UnionPayConfig;
import com.hzw.saas.common.pay.unionpay.sdk.AcpService;
import lombok.extern.slf4j.Slf4j;

/**
 * 银联支付执行器
 *
 * @author zzl
 * @since 2020-10-02
 */
@Slf4j
public class UnionPayExecutor {


    /**
     * 银联网关支付接口（跳转支付）
     *
     * @param content 请求参数
     * @return 跳转支付html（完整的页面）
     */
    public static String frontPay(UnionPayReqContent content) throws TradeException {
        log.info("union front pay...");
        content.setTxnType("01");
        content.setTxnSubType("01");
        Map<String, String> requestMap = content.buildContent();

        //对请求参数进行签名并生成html表单
        Map<String, String> submitFromData = AcpService.sign(requestMap, UnionPayConfig.config().getEncoding());
        // 银联的前台地址
        String requestFrontUrl = UnionPayConfig.config().getFrontTransUrl();
        //生成自动跳转的Html表单
        String html = AcpService.createAutoFormHtml(requestFrontUrl, submitFromData, UnionPayConfig.config().getEncoding());

        log.info("union front pay html: " + html);
        return html;
    }

    /**
     * 银联退款接口
     *
     * @param content 请求参数
     * @throws TradeException
     */
    public static TradeStatus refund(UnionRefundReqContent content) throws TradeException {
        log.info("union refund...");
        content.setTxnType("04"); // 交易类型 04退货
        content.setTxnSubType("00"); //交易子类型 00 默认
        Map<String, String> requestMap = content.buildContent();

        /* 对请求参数进行签名并发送http post请求，接收同步应答报文 */
        Map<String, String> reqData = AcpService.sign(requestMap, UnionPayConfig.config().getEncoding());
        String refundUrl = UnionPayConfig.config().getBackTransUrl();

        Map<String, String> rspData = AcpService.post(reqData, refundUrl, UnionPayConfig.config().getEncoding());

        if (rspData.isEmpty()) {
            throw new TradeException("银联退款请求异常，未获取到返回报文或返回http状态码非200");
        }

        if (!UnionPayUtil.notifySignCheck(rspData)) {
            throw new TradeException("银联退款请求异常，返回结果签名无法通过校验");
        }
        log.debug("refund post response 签名验证成功，queryId=" + rspData.get("queryId"));

        TradeStatus tradeStatus = new TradeStatus();
        tradeStatus.setPayType(PayType.UNION_PAY);
        tradeStatus.setPayNo(rspData.get("orderId"));
        try {
            tradeStatus.setCreateTime(new SimpleDateFormat(UnionPayConfig.config().getDataFormat()).parse(reqData.get("txnTime")));
        } catch (ParseException e) {
            e.printStackTrace();
            log.error("union pay query data format error", e);
        }
        if ("00".equals(rspData.get("respCode"))) {//如果查询交易成功
            //处理被查询交易的应答码逻辑
            String origRespCode = rspData.get("origRespCode");
            if ("00".equals(origRespCode)) {
                //交易成功，更新商户订单状态
                tradeStatus.setTradeStatus(TradeStatusEnum.REFUND_SUCCESS);
            } else if ("03".equals(origRespCode) || "04".equals(origRespCode) || "05".equals(origRespCode)) {
                //需再次发起交易状态查询交易
                //TODO
                tradeStatus.setTradeStatus(TradeStatusEnum.UNKNOWN);
            } else {
                //其他应答码为失败请排查原因
                //TODO
                tradeStatus.setTradeStatus(TradeStatusEnum.UNKNOWN);
            }
        } else {//查询交易本身失败，或者未查到原交易，检查查询交易报文要素
            //TODO
            tradeStatus.setTradeStatus(TradeStatusEnum.UNKNOWN);
        }
        log.debug("UNION_PAY refund finished... status=" + tradeStatus);
        return tradeStatus;
    }

    /**
     * 银联查询接口
     *
     * @param content 请求参数
     * @throws TradeException
     */
    public static TradeStatus query(UnionQueryReqContent content) throws TradeException {
        log.debug("union query...");
        content.setTxnType("00");
        content.setTxnSubType("00");
        Map<String, String> requestMap = content.buildContent();

        /* 对请求参数进行签名并发送http post请求，接收同步应答报文 */
        Map<String, String> reqData = AcpService.sign(requestMap, UnionPayConfig.config().getEncoding());

        String url = UnionPayConfig.config().getSingleQueryUrl();
        Map<String, String> rspData = AcpService.post(reqData, url, UnionPayConfig.config().getEncoding());

        if (rspData.isEmpty()) {
            throw new TradeException("银联查询请求异常，未获取到返回报文或返回http状态码非200");
        }

        if (!UnionPayUtil.notifySignCheck(rspData)) {
            throw new TradeException("银联查询请求异常，返回结果签名无法通过校验");
        }

        TradeStatus tradeStatus = new TradeStatus();
        tradeStatus.setPayType(PayType.UNION_PAY);
        tradeStatus.setPayNo(rspData.get("orderId"));
        tradeStatus.setBizPayNo(rspData.get("queryId"));
        try {
            tradeStatus.setCreateTime(new SimpleDateFormat(UnionPayConfig.config().getDataFormat()).parse(reqData.get("txnTime")));
        } catch (ParseException e) {
            e.printStackTrace();
            log.error("union pay query data format error", e);
        }
        if ("00".equals(rspData.get("respCode"))) {//如果查询交易成功
            //处理被查询交易的应答码逻辑
            String origRespCode = rspData.get("origRespCode");
            if ("00".equals(origRespCode)) {
                //交易成功
                tradeStatus.setTradeStatus(TradeStatusEnum.TRADE_SUCCESS);
            } else if ("03".equals(origRespCode) || "04".equals(origRespCode) || "05".equals(origRespCode)) {
                //需再次发起交易状态查询交易
                tradeStatus.setTradeStatus(TradeStatusEnum.UNKNOWN);
            } else {
                tradeStatus.setTradeStatus(TradeStatusEnum.UNKNOWN);
            }
        } else {//查询交易本身失败，或者未查到原交易，检查查询交易报文要素
            log.error("银联查询请求异常，查询交易本身失败，或者未查到原交易，检查查询交易报文要素");
            tradeStatus.setTradeStatus(TradeStatusEnum.UNKNOWN);
        }
        log.debug("UNION_PAY query finished... status=" + tradeStatus);
        return tradeStatus;
    }


}
